package com.wangfugui.mybatisplus.stock;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.util.List;

public class StockVisualizationJava8 {
    
    public static void main(String[] args) {
        String htmlContent = HTML.text;
        
        List<StockInfo> stockList = extractStockData(htmlContent);
        
        // 数据分析
        Map<String, Integer> reasonStats = new HashMap<>();
        Map<String, Integer> industryStats = new HashMap<>();
        Map<String, Integer> boardStats = new HashMap<>();
        
        for (StockInfo stock : stockList) {
            // 动因统计
            String mainReason = extractMainReason(stock.getReason());
            Integer reasonCount = reasonStats.get(mainReason);
            reasonStats.put(mainReason, reasonCount == null ? 1 : reasonCount + 1);
            
            // 行业统计
            String industry = extractIndustry(stock.getReason());
            Integer industryCount = industryStats.get(industry);
            industryStats.put(industry, industryCount == null ? 1 : industryCount + 1);
            
            // 板块统计
            String board = extractBoard(stock.getFullCode());
            Integer boardCount = boardStats.get(board);
            boardStats.put(board, boardCount == null ? 1 : boardCount + 1);
        }
        
        // 控制台输出
        printConsoleAnalysis(stockList, reasonStats, industryStats, boardStats);
        
        // 图形界面显示
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                createAndShowGUI(stockList, reasonStats, industryStats, boardStats);
            }
        });
    }
    
    public static List<StockInfo> extractStockData(String htmlContent) {
        List<StockInfo> stockList = new ArrayList<>();
        
        try {
            Document doc = Jsoup.parse(htmlContent);
            Elements rows = doc.select("table.w-100p.watch-table tbody tr");
            
            for (Element row : rows) {
                if (row.select("th").size() > 0) continue;
                
                Elements cells = row.select("td");
                if (cells.size() >= 5) {
                    // 提取股票代码和名称
                    String name = cells.get(0).select("div.f-w-b").text().trim();
                    String fullCode = cells.get(0).select("div.f-s-12.c-666.f-w-n").text().trim();
                    String code = fullCode.replaceAll("[^0-9]", "");
                    
                    // 提取价格和涨跌幅
                    String price = cells.get(1).text().trim();
                    String changePercent = cells.get(2).text().trim();
                    
                    // 提取动因
                    Element reasonElement = cells.get(4).selectFirst("div.watch-quote-reason");
                    String reason = reasonElement != null ? 
                        reasonElement.attr("title") : cells.get(4).text().trim();
                    
                    // 提取连续涨停数
                    String limitUpDays = cells.get(3).text().trim();
                    
                    stockList.add(new StockInfo(code, name, reason, limitUpDays, fullCode, price, changePercent));
                }
            }
            
        } catch (Exception e) {
            System.err.println("解析错误: " + e.getMessage());
        }
        
        return stockList;
    }
    
    private static String extractMainReason(String reason) {
        if (reason == null || reason.isEmpty()) return "其他";
        
        int pipeIndex = reason.indexOf("|");
        if (pipeIndex > 0) {
            return reason.substring(0, pipeIndex).trim();
        }
        
        String[] keywords = {"生物柴油", "PEEK", "有机硅", "光伏", "IDC电源", "光通信", 
                           "商业航天", "六氟磷酸锂", "固态电池", "ST股", "并购重组", "机器人",
                           "半导体", "化工", "新能源", "医药", "基建"};
        
        for (String keyword : keywords) {
            if (reason.contains(keyword)) {
                return keyword;
            }
        }
        
        return "其他";
    }
    
    private static String extractIndustry(String reason) {
        if (reason.contains("光伏") || reason.contains("新能源") || reason.contains("电池")) {
            return "新能源";
        } else if (reason.contains("半导体") || reason.contains("芯片") || reason.contains("电子")) {
            return "半导体";
        } else if (reason.contains("化工") || reason.contains("材料") || reason.contains("磷")) {
            return "化工";
        } else if (reason.contains("医药") || reason.contains("医疗") || reason.contains("生物")) {
            return "医药";
        } else if (reason.contains("ST")) {
            return "ST股";
        } else {
            return "其他";
        }
    }
    
    private static String extractBoard(String fullCode) {
        if (fullCode.startsWith("sh")) {
            return "上海主板";
        } else if (fullCode.startsWith("sz")) {
            return "深圳主板";
        } else if (fullCode.startsWith("bj")) {
            return "北京交易所";
        } else {
            return "其他";
        }
    }
    
    private static void printConsoleAnalysis(List<StockInfo> stocks, 
                                           Map<String, Integer> reasonStats,
                                           Map<String, Integer> industryStats,
                                           Map<String, Integer> boardStats) {
        System.out.println("🎯 涨停股票分析报告");
        System.out.println("=" + repeatString("=", 120));
        System.out.printf("📊 总计: %d 只涨停股票%n%n", stocks.size());
        
        // 动因统计
        System.out.println("🏷️  涨停动因分布:");
        System.out.println("-" + repeatString("-", 79));
        printStatMap(reasonStats, stocks.size());
        
        // 行业统计
        System.out.println("\n🏭 行业分布:");
        System.out.println("-" + repeatString("-", 79));
        printStatMap(industryStats, stocks.size());
        
        // 板块统计
        System.out.println("\n📈 交易所分布:");
        System.out.println("-" + repeatString("-", 79));
        printStatMap(boardStats, stocks.size());
        
        // 连板统计
        System.out.println("\n🔥 连板情况:");
        System.out.println("-" + repeatString("-", 79));
        printLimitUpStats(stocks);
        
        // 详细列表
        System.out.println("\n📋 详细股票列表:");
        System.out.println("-" + repeatString("-", 119));
        printStockTable(stocks);
    }
    
    private static void printStatMap(Map<String, Integer> statMap, int total) {
        List<Map.Entry<String, Integer>> sorted = new ArrayList<>(statMap.entrySet());
        Collections.sort(sorted, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) {
                return b.getValue().compareTo(a.getValue());
            }
        });
        
        for (Map.Entry<String, Integer> entry : sorted) {
            double percentage = (entry.getValue() * 100.0) / total;
            String bar = repeatString("█", (int) (percentage / 5));
            System.out.printf("%-15s: %2d 只 %5.1f%% %s%n", 
                entry.getKey(), entry.getValue(), percentage, bar);
        }
    }
    
    private static void printLimitUpStats(List<StockInfo> stocks) {
        Map<String, Integer> limitUpMap = new HashMap<>();
        for (StockInfo stock : stocks) {
            String days = stock.getLimitUpDays();
            Integer count = limitUpMap.get(days);
            limitUpMap.put(days, count == null ? 1 : count + 1);
        }
        
        List<Map.Entry<String, Integer>> sorted = new ArrayList<>(limitUpMap.entrySet());
        Collections.sort(sorted, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) {
                return Integer.parseInt(a.getKey()) - Integer.parseInt(b.getKey());
            }
        });
        
        for (Map.Entry<String, Integer> entry : sorted) {
            System.out.printf("连板%s天: %2d 只股票", entry.getKey(), entry.getValue());
            if ("1".equals(entry.getKey())) {
                System.out.print(" 🆕");
            } else if (Integer.parseInt(entry.getKey()) >= 5) {
                System.out.print(" 🔥");
            }
            System.out.println();
        }
    }
    
    private static void printStockTable(List<StockInfo> stocks) {
        System.out.printf("%-4s %-8s %-12s %-8s %-8s %-10s %s%n",
            "序号", "代码", "名称", "价格", "涨跌幅", "连板", "主要动因");
        System.out.println(repeatString("-", 119));
        
        for (int i = 0; i < stocks.size(); i++) {
            StockInfo stock = stocks.get(i);
            String mainReason = extractMainReason(stock.getReason());
            String emoji = getStockEmoji(stock);
            
            System.out.printf("%2d.  %-6s %-10s %-8s %-8s %-10s %s %s%n",
                i + 1,
                stock.getFullCode(),
                stock.getName(),
                stock.getPrice(),
                stock.getChangePercent(),
                stock.getLimitUpDays() + "天",
                emoji,
                mainReason
            );
        }
    }
    
    private static String getStockEmoji(StockInfo stock) {
        if (stock.getName().contains("ST")) return "⚠️";
        if (Integer.parseInt(stock.getLimitUpDays()) >= 5) return "🔥";
        if (stock.getChangePercent().contains("+20")) return "🚀";
        return "📈";
    }
    
    // Java 8 兼容的字符串重复方法
    private static String repeatString(String str, int count) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < count; i++) {
            sb.append(str);
        }
        return sb.toString();
    }
    
    // 图形界面
    private static void createAndShowGUI(List<StockInfo> stocks, 
                                       Map<String, Integer> reasonStats,
                                       Map<String, Integer> industryStats,
                                       Map<String, Integer> boardStats) {
        JFrame frame = new JFrame("涨停股票可视化分析");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1200, 800);
        
        JTabbedPane tabbedPane = new JTabbedPane();
        
        // 添加各个图表页面
        tabbedPane.addTab("📊 概览", createOverviewPanel(stocks));
        tabbedPane.addTab("🏷️ 动因分析", createReasonChartPanel(reasonStats));
        tabbedPane.addTab("🏭 行业分布", createIndustryChartPanel(industryStats));
        tabbedPane.addTab("📈 交易所", createBoardChartPanel(boardStats));
        tabbedPane.addTab("📋 详细数据", createStockTablePanel(stocks));
        
        frame.add(tabbedPane);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    private static JPanel createOverviewPanel(List<StockInfo> stocks) {
        JPanel panel = new JPanel(new BorderLayout());
        
        // 顶部统计信息
        JPanel statsPanel = new JPanel(new GridLayout(2, 3, 10, 10));
        statsPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        
        statsPanel.add(createStatCard("总涨停数", String.valueOf(stocks.size()), "📈", Color.BLUE));
        
        int stCount = 0;
        int highLimitCount = 0;
        for (StockInfo stock : stocks) {
            if (stock.getName().contains("ST")) stCount++;
            if (stock.getChangePercent().contains("+20")) highLimitCount++;
        }
        
        statsPanel.add(createStatCard("ST股票", String.valueOf(stCount), "⚠️", Color.ORANGE));
        statsPanel.add(createStatCard("20%涨停", String.valueOf(highLimitCount), "🚀", Color.RED));
        
        // 连板统计
        Map<String, Integer> limitUpMap = new HashMap<>();
        for (StockInfo stock : stocks) {
            String days = stock.getLimitUpDays();
            Integer count = limitUpMap.get(days);
            limitUpMap.put(days, count == null ? 1 : count + 1);
        }
        
        int multiLimitCount = 0;
        for (Map.Entry<String, Integer> entry : limitUpMap.entrySet()) {
            if (Integer.parseInt(entry.getKey()) > 1) {
                multiLimitCount += entry.getValue();
            }
        }
        
        statsPanel.add(createStatCard("连板股票", String.valueOf(multiLimitCount), "🔥", Color.GREEN));
        statsPanel.add(createStatCard("首板股票", String.valueOf(limitUpMap.get("1")), "🆕", Color.CYAN));
        
        panel.add(statsPanel, BorderLayout.NORTH);
        
        // 中间显示一些关键股票
        JTextArea textArea = new JTextArea();
        textArea.setEditable(false);
        textArea.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        
        StringBuilder sb = new StringBuilder();
        sb.append("🔥 重点涨停股票:\n\n");
        
        // 找出连板数高的股票
        List<StockInfo> sortedStocks = new ArrayList<>(stocks);
        Collections.sort(sortedStocks, new Comparator<StockInfo>() {
            @Override
            public int compare(StockInfo a, StockInfo b) {
                return Integer.parseInt(b.getLimitUpDays()) - Integer.parseInt(a.getLimitUpDays());
            }
        });
        
        for (int i = 0; i < Math.min(10, sortedStocks.size()); i++) {
            StockInfo stock = sortedStocks.get(i);
            sb.append(String.format("• %s (%s) 连板%s天 %s\n",
                stock.getName(), stock.getFullCode(), stock.getLimitUpDays(),
                extractMainReason(stock.getReason())));
        }
        
        textArea.setText(sb.toString());
        panel.add(new JScrollPane(textArea), BorderLayout.CENTER);
        
        return panel;
    }
    
    private static JPanel createStatCard(String title, String value, String emoji, Color color) {
        JPanel card = new JPanel(new BorderLayout());
        card.setBorder(BorderFactory.createCompoundBorder(
            BorderFactory.createLineBorder(color, 2),
            BorderFactory.createEmptyBorder(10, 10, 10, 10)
        ));
        card.setBackground(Color.WHITE);
        
        JLabel emojiLabel = new JLabel(emoji);
        emojiLabel.setFont(new Font("Segoe UI Emoji", Font.PLAIN, 24));
        emojiLabel.setHorizontalAlignment(SwingConstants.CENTER);
        
        JLabel valueLabel = new JLabel(value);
        valueLabel.setFont(new Font("微软雅黑", Font.BOLD, 24));
        valueLabel.setHorizontalAlignment(SwingConstants.CENTER);
        
        JLabel titleLabel = new JLabel(title);
        titleLabel.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        titleLabel.setHorizontalAlignment(SwingConstants.CENTER);
        
        card.add(emojiLabel, BorderLayout.NORTH);
        card.add(valueLabel, BorderLayout.CENTER);
        card.add(titleLabel, BorderLayout.SOUTH);
        
        return card;
    }
    
    private static JPanel createReasonChartPanel(Map<String, Integer> reasonStats) {
        return createChartPanel("涨停动因分布", reasonStats, "动因", "数量");
    }
    
    private static JPanel createIndustryChartPanel(Map<String, Integer> industryStats) {
        return createChartPanel("行业分布", industryStats, "行业", "数量");
    }
    
    private static JPanel createBoardChartPanel(Map<String, Integer> boardStats) {
        return createChartPanel("交易所分布", boardStats, "交易所", "数量");
    }
    
    private static JPanel createChartPanel(String title, Map<String, Integer> data, 
                                         String xLabel, String yLabel) {
        JPanel panel = new JPanel(new BorderLayout());
        panel.add(new ChartComponent(data, title, xLabel, yLabel), BorderLayout.CENTER);
        return panel;
    }
    
    private static JPanel createStockTablePanel(List<StockInfo> stocks) {
        JPanel panel = new JPanel(new BorderLayout());
        
        String[] columnNames = {"代码", "名称", "价格", "涨跌幅", "连板天数", "主要动因"};
        Object[][] rowData = new Object[stocks.size()][6];
        
        for (int i = 0; i < stocks.size(); i++) {
            StockInfo stock = stocks.get(i);
            rowData[i][0] = stock.getFullCode();
            rowData[i][1] = stock.getName();
            rowData[i][2] = stock.getPrice();
            rowData[i][3] = stock.getChangePercent();
            rowData[i][4] = stock.getLimitUpDays();
            rowData[i][5] = extractMainReason(stock.getReason());
        }
        
        JTable table = new JTable(rowData, columnNames);
        table.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        table.setRowHeight(25);
        
        JScrollPane scrollPane = new JScrollPane(table);
        panel.add(scrollPane, BorderLayout.CENTER);
        
        return panel;
    }
    
    // 股票信息类
    static class StockInfo {
        private String code;
        private String name;
        private String reason;
        private String limitUpDays;
        private String fullCode;
        private String price;
        private String changePercent;
        
        public StockInfo(String code, String name, String reason, String limitUpDays, 
                        String fullCode, String price, String changePercent) {
            this.code = code;
            this.name = name;
            this.reason = reason;
            this.limitUpDays = limitUpDays;
            this.fullCode = fullCode;
            this.price = price;
            this.changePercent = changePercent;
        }
        
        public String getCode() { return code; }
        public String getName() { return name; }
        public String getReason() { return reason; }
        public String getLimitUpDays() { return limitUpDays; }
        public String getFullCode() { return fullCode; }
        public String getPrice() { return price; }
        public String getChangePercent() { return changePercent; }
    }
}

// 图表绘制组件
class ChartComponent extends JPanel {
    private Map<String, Integer> data;
    private String title;
    private String xLabel;
    private String yLabel;
    
    public ChartComponent(Map<String, Integer> data, String title, String xLabel, String yLabel) {
        this.data = data;
        this.title = title;
        this.xLabel = xLabel;
        this.yLabel = yLabel;
        setPreferredSize(new Dimension(800, 500));
        setBackground(Color.WHITE);
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        
        int width = getWidth();
        int height = getHeight();
        int padding = 50;
        int chartWidth = width - 2 * padding;
        int chartHeight = height - 2 * padding;
        
        // 绘制标题
        g2d.setFont(new Font("微软雅黑", Font.BOLD, 16));
        g2d.drawString(title, width / 2 - g2d.getFontMetrics().stringWidth(title) / 2, padding - 10);
        
        // 绘制坐标轴标签
        g2d.setFont(new Font("微软雅黑", Font.PLAIN, 12));
        g2d.drawString(xLabel, width / 2 - g2d.getFontMetrics().stringWidth(xLabel) / 2, height - 10);
        g2d.drawString(yLabel, 10, height / 2);
        
        if (data == null || data.isEmpty()) return;
        
        // 找出最大值
        int maxValue = 0;
        for (int value : data.values()) {
            if (value > maxValue) maxValue = value;
        }
        
        // 绘制柱状图
        List<Map.Entry<String, Integer>> entries = new ArrayList<>(data.entrySet());
        Collections.sort(entries, new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) {
                return b.getValue().compareTo(a.getValue());
            }
        });
        
        int barWidth = chartWidth / Math.max(entries.size(), 1);
        Color[] colors = {Color.RED, Color.BLUE, Color.GREEN, Color.ORANGE, Color.MAGENTA, Color.CYAN};
        
        for (int i = 0; i < entries.size(); i++) {
            Map.Entry<String, Integer> entry = entries.get(i);
            String key = entry.getKey();
            int value = entry.getValue();
            
            int barHeight = (int) ((double) value / maxValue * chartHeight);
            int x = padding + i * barWidth;
            int y = height - padding - barHeight;
            
            // 绘制柱子
            g2d.setColor(colors[i % colors.length]);
            g2d.fillRect(x + 5, y, barWidth - 10, barHeight);
            
            // 绘制数值
            g2d.setColor(Color.BLACK);
            String valueStr = String.valueOf(value);
            g2d.drawString(valueStr, x + barWidth / 2 - g2d.getFontMetrics().stringWidth(valueStr) / 2, y - 5);
            
            // 绘制标签
            g2d.drawString(key, x + barWidth / 2 - g2d.getFontMetrics().stringWidth(key) / 2, height - padding + 20);
        }
        
        // 绘制坐标轴
        g2d.setColor(Color.BLACK);
        g2d.drawLine(padding, height - padding, width - padding, height - padding); // X轴
        g2d.drawLine(padding, height - padding, padding, padding); // Y轴
    }
}